package jellyfishumbrella.tikis;

import static org.lwjgl.opengl.GL11.GL_LINE_LOOP;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;

import megamu.mesh.Region;
import megamu.mesh.Site;

import com.jellyfishumbrella.GL.MeshGL;
import com.jellyfishumbrella.GL.PolygonGroup;
import com.jellyfishumbrella.GL.Renderable;
import com.jellyfishumbrella.GL.RendererGL;
import com.jellyfishumbrella.GL.ThreadLoop;
import com.jellyfishumbrella.GL.UberPoly;
import com.jellyfishumbrella.GL.Vector3d;
import com.jellyfishumbrella.noise.FastNoise;
import com.jellyfishumbrella.util.Trace;

import delaunay.Delaunay2;

/**
 * TODO Put here a description of what this class does.
 * 
 * @author 500441547. Created Sep 4, 2012.
 */
public class VorLand2D {
	static double				n				= 1.0;

	protected final int			NUM_SIDE_POINTS	= 7;
	protected final int			COASTBORDER	= 2;
	protected final int			MAX_WIDTH		= 3000;
	protected final int			MAX_HEIGHT		= 3000;

	public Site[][]				sites			= new Site[NUM_SIDE_POINTS][NUM_SIDE_POINTS];
	protected Site				center;

	protected Delaunay2			voronoi2;

	protected ArrayList<MeshGL>	meshes			= new ArrayList<MeshGL>();

	protected PolygonGroup		landscapePointsPG;
	protected PolygonGroup		landscapeGridPG;

	public GameLogic			logic;

	public boolean				READY			= false;

	public int					glMode			= GL_LINE_LOOP;

	public VorLand2D() {
		super();
	}

	public VorLand2D(GameLogic logic) {
		super();
		this.logic = logic;

		VorLand2DThread vorLand2DThread = new VorLand2DThread("VorLand2D", logic);
		vorLand2DThread.start();
	}

	public class VorLand2DThread extends ThreadLoop {
		GameLogic	logic;
		VorLand2D	vorLand2D;

		public VorLand2DThread(String name, GameLogic logic) {
			super(name);
			this.logic = logic;
			logic.allThreads.add(this);
		}

		public void run() {
			voronoi2 = new Delaunay2();

			createTerrainPoints();
			for (int j = 0; j < NUM_SIDE_POINTS; j++) {
				for (int i = 0; i < NUM_SIDE_POINTS; i++) {
					Site currSite = sites[i][j];
					if (currSite.doVoronoi) {
						voronoi2.addSite(currSite);
					}
				}
			}
			ArrayList<Region> regions = voronoi2.getRegions(sites);
			for (Region currRegion : regions) {
				if (currRegion.site.isCenter) {
					center = currRegion.site;
				}
			}
			sendPolygonsToGL(regions);
			READY = true;
		}
	}

	public void cycleMode() {
		glMode = RendererGL.glModeQ.poll();
		RendererGL.glModeQ.offer(glMode);
		for (MeshGL currMesh : meshes) {
			currMesh.glMode = glMode;
		}
	}

	public void createTerrainPoints() {
		Trace.getCurrentMethodName();
		Site newSite;
		int octaves = 4;

		clearAllMeshes();

		float w = MAX_WIDTH / (float) NUM_SIDE_POINTS;
		float h = MAX_HEIGHT / (float) NUM_SIDE_POINTS;
		ArrayList rect = new ArrayList();

		int k = 0;
		for (int j = 0; j < NUM_SIDE_POINTS; j++) {
			for (int i = 0; i < NUM_SIDE_POINTS; i++) {

				double X2 = w * i - MAX_WIDTH / 2;
				double Z2 = h * j - MAX_HEIGHT / 2;

				double X3 = X2 + w * (FastNoise.noiseMinMax(X2, Z2, octaves, false, false, -.45, .45));
				double Z3 = Z2 + h * (FastNoise.noiseMinMax(Z2, X2, octaves, false, false, -.45, .45));

				newSite = new Site(X3, Z3);
				newSite.index = k++;
				newSite.iIndex = i;
				newSite.jIndex = j;

				// sites.add(newSite);
				sites[i][j] = newSite;

				if (i == NUM_SIDE_POINTS / 2 && j == NUM_SIDE_POINTS / 2) {
					center = newSite;
					System.out.println("Found center " + i + " ," + j);
				}
			}
		}

		center.doVoronoi = true;
		for (int i = -COASTBORDER; i <= COASTBORDER; i++) {
			for (int j = -COASTBORDER; j <= COASTBORDER; j++) {
				//sites[center.iIndex + i][center.jIndex + j].doVoronoi = true;
			}
		}
	}

	public void clearAllMeshes() {
		for (MeshGL currMesh : meshes) {
			if (logic.renderGL.contains((Renderable) currMesh)) {
				logic.renderGL.remove(currMesh);
			}
			currMesh.clear();
		}
		meshes.clear();
	}

	public void flipNormals() {
		n = -n;
		for (int j = 0; j < NUM_SIDE_POINTS; j++) {
			for (int i = 0; i < NUM_SIDE_POINTS; i++) {
				Site currSite = sites[i][j];
				Region currRegion = currSite.region;
				if (currRegion != null) {
					currRegion.alignNormals(new Vector3d(0, n, 0));
				}
			}
		}
	}

	public void sendPolygonsToGL(ArrayList<Region> regions) {
		Trace.getCurrentMethodName();

		clearAllMeshes();

		// System.out.println("There are " + regions.length + " regions.");
		// synchronized (currMesh.polyGroups) {
		MeshGL currMesh = new MeshGL();
		meshes.add(currMesh);

		synchronized (currMesh.uberPolys) {
			currMesh.uberPolys = new HashSet<UberPoly>();
		}

		for (Region currRegion : regions) {
			currMesh.glMode = glMode;

			currRegion.parentMesh = currMesh;

			currMesh.uberPolys.add(currRegion);

			currRegion.setLOD(1);

			currRegion.setSurface("ocean");
			// currRegion.setSurface("lava");
		}

		logic.renderGL.add(currMesh);
		currMesh.refreshVerts = true;
		currMesh.refreshIndices = true;
		// }
		// }
	}
}
